<!-- 主页面 -->
<template>
  <div class="w-full h-full p-4 flex flex-col items-center">
    <header class="text-3xl">2048小游戏</header>
    <footer
      ref="target"
      class="m-4 w-[90%] max-w-[460px] h-[50%] max-h-[460px] p-[10px] bg-slate-300 flex flex-wrap justify-between items-center"
    >
      <div
        v-for="item in arr"
        :key="item.index"
        :style="{ 'background-color': refreshColor(item.value) }"
        class="w-[23%] h-[23%] text-2xl flex items-center justify-center"
      >
        {{ item.value }}
      </div>
    </footer>
    <div>
      <button
        class="w-20 h-10 bg-orange-50"
        style="border: 1px solid red; border-radius: 5px"
        @click="init"
      >
        重新开始
      </button>
      当前得分：<span class="text-lg">{{ score }}</span>
      <!-- <div>direction:{{ direction }}</div> -->
    </div>
  </div>
</template>

<script setup lang="ts">
import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
import { useSwipe } from '@vueuse/core'
/**
 * 类型定义
 */
export interface arrType {
  index: number
  value: number
}

const arr = ref<Array<arrType>>([
  { index: 0, value: 0 },
  { index: 1, value: 0 },
  { index: 2, value: 0 },
  { index: 3, value: 0 },
  { index: 4, value: 0 },
  { index: 5, value: 0 },
  { index: 6, value: 0 },
  { index: 7, value: 0 },
  { index: 8, value: 0 },
  { index: 9, value: 0 },
  { index: 10, value: 0 },
  { index: 11, value: 0 },
  { index: 12, value: 0 },
  { index: 13, value: 0 },
  { index: 14, value: 0 },
  { index: 15, value: 0 }
])
const score = ref<number>(0)
let value0Arr: Array<arrType> = []

// 数组为0值的数组
watch(
  () => arr,
  () => {
    value0Arr = arr.value.filter((item) => {
      return item.value === 0
    })
  },
  {
    deep: true,
    immediate: true
  }
)

onMounted(() => {
  init()
})

onUnmounted(() => {
  window.removeEventListener('keydown', keyDown)
})

// 初始化
const init = () => {
  score.value = 0
  arr.value.forEach((item) => (item.value = 0))
  window.addEventListener('keydown', keyDown)
  nextTick(() => {
    createRandomNumber(2)
  })
}

// 在值为0的地方，生成随机数
const createRandomNumber = (num?: number) => {
  let cellValue: number
  if (!num) {
    //获取2或者4,2出现改率为4两倍
    const randomNumber = Math.random()
    if (randomNumber < 0.67) {
      cellValue = 2
    } else {
      cellValue = 4
    }
  } else {
    cellValue = num
  }

  // 值随机放置在一个为0的cell
  const position = Math.floor(Math.random() * value0Arr.length)
  arr.value[value0Arr[position].index].value = cellValue
}

// 刷新颜色
const refreshColor = (value: number) => {
  // console.log(items.eq(i).parent().index());
  switch (value) {
    case 0:
      return '#ffffff'
    case 2:
      return 'rgb(250, 225, 188)'
    case 4:
      return 'rgb(202, 240, 240)'
    case 8:
      return 'rgb(117, 231, 193)'
    case 16:
      return 'rgb(240, 132, 132)'
    case 32:
      return 'rgb(181, 240, 181)'
    case 64:
      return 'rgb(182, 210, 246)'
    case 128:
      return 'rgb(255, 207, 126)'
    case 256:
      return 'rgb(250, 216, 216)'
    case 512:
      return 'rgb(124, 183, 231)'
    case 1024:
      return 'rgb(225, 219, 215)'
    case 2048:
      return 'rgb(221, 160, 221)'
    case 4096:
      return 'rgb(250, 139, 176)'
  }
}

/**
 * 移动数组值；合并，判断是否继续生成；计算得分
 */
const moveItem = (direction: string) => {
  let isWin: Boolean = false
  if (direction == 'right' || direction == 'left') {
    for (let i = 0; i < 4; i++) {
      let itemArr: Array<number> = [
        arr.value[i * 4].value,
        arr.value[i * 4 + 1].value,
        arr.value[i * 4 + 2].value,
        arr.value[i * 4 + 3].value
      ].filter((item: number) => item != 0)

      const length = itemArr.length
      if (length > 1) {
        if (direction == 'right') {
          for (let j = length; j > 1; j--) {
            if (!itemArr[j - 1]) {
              continue
            }
            if (itemArr[j - 1] == itemArr[j - 2]) {
              itemArr[j - 1] = 2 * itemArr[j - 1]
              score.value += itemArr[j - 1]
              if (itemArr[j - 1] === 2048) isWin = true
              itemArr[j - 2] = 0
            }
          }
        } else {
          for (let j = 0; j < length - 1; j++) {
            if (!itemArr[j]) {
              continue
            }
            if (itemArr[j] == itemArr[j + 1]) {
              itemArr[j] = 2 * itemArr[j]
              score.value += itemArr[j]
              if (itemArr[j] === 2048) isWin = true
              itemArr[j + 1] = 0
            }
          }
        }
      }
      itemArr = itemArr.filter((item: number) => item != 0)
      const finalLength = itemArr.length
      if (finalLength != 4) {
        for (let k = 0; k < 4 - finalLength; k++) {
          if (direction == 'right') {
            itemArr.unshift(0)
          } else {
            itemArr.push(0)
          }
        }
      }
      arr.value[i * 4].value = itemArr[0]
      arr.value[i * 4 + 1].value = itemArr[1]
      arr.value[i * 4 + 2].value = itemArr[2]
      arr.value[i * 4 + 3].value = itemArr[3]
    }
  } else {
    for (let i = 0; i < 4; i++) {
      let itemArr = [
        arr.value[i + 0].value,
        arr.value[i + 4].value,
        arr.value[i + 8].value,
        arr.value[i + 12].value
      ].filter((item: number) => item != 0)
      const length = itemArr.length
      if (length > 1) {
        if (direction == 'down') {
          for (let j = length; j > 1; j--) {
            if (!itemArr[j - 1]) {
              continue
            }
            if (itemArr[j - 1] == itemArr[j - 2]) {
              itemArr[j - 1] = 2 * itemArr[j - 1]
              score.value += itemArr[j - 1]
              if (itemArr[j - 1] === 2048) isWin = true
              itemArr[j - 2] = 0
            }
          }
        } else {
          for (let j = 0; j < length - 1; j++) {
            if (!itemArr[j]) {
              continue
            }
            if (itemArr[j] == itemArr[j + 1]) {
              itemArr[j] = 2 * itemArr[j]
              score.value += itemArr[j]
              if (itemArr[j] === 2048) isWin = true
              itemArr[j + 1] = 0
            }
          }
        }
      }
      itemArr = itemArr.filter((item: number) => item != 0)
      const finalLength = itemArr.length
      if (finalLength != 4) {
        for (let k = 0; k < 4 - finalLength; k++) {
          if (direction == 'down') {
            itemArr.unshift(0)
          } else {
            itemArr.push(0)
          }
        }
      }
      arr.value[i + 0].value = itemArr[0]
      arr.value[i + 4].value = itemArr[1]
      arr.value[i + 8].value = itemArr[2]
      arr.value[i + 12].value = itemArr[3]
    }
  }

  nextTick(() => {
    if (value0Arr.length > 0) {
      nextTick(() => {
        createRandomNumber()
      })
    }
    if (isWin) {
      console.log('胜利！')
      alert('胜利！')
      gameOver()
      return
    }
    if (value0Arr.length == 0) {
      const flag = isLoser()
      if (flag) {
        console.log('游戏结束！')
        gameOver()
        alert('游戏结束！')
        return
      }
    }
  })
}

// 判断输赢
const isLoser = () => {
  let flag: Boolean = true
  // 竖向判断
  for (let i = 0; i < 12; i++) {
    if (arr.value[i].value === 0) continue
    if (arr.value[i].value === arr.value[i + 4].value) {
      flag = false
      break
    }
  }
  // 横向判断
  for (let i = 0; i < 15; i++) {
    if (arr.value[i].value === 0 || [3, 7, 11].includes(i)) continue
    if (arr.value[i].value === arr.value[i + 1].value) {
      flag = false
      break
    }
  }
  //   console.log(flag, 'flag')
  return flag
}

const gameOver = () => {
  window.removeEventListener('keydown', keyDown)
}

// 监听上下左右事件
const keyDown = (event: any) => {
  let direction: string = ''
  switch (event.key) {
    case 'ArrowUp':
      direction = 'up'
      break
    case 'ArrowDown':
      direction = 'down'
      break
    case 'ArrowLeft':
      direction = 'left'
      break
    case 'ArrowRight':
      direction = 'right'
      break
  }
  if (direction) {
    moveItem(direction)
  }
}

// 移动端网页触摸移动
const target = ref<HTMLElement | null>(null)
export type UseSwipeDirection = 'up' | 'down' | 'left' | 'right' | 'none'
const { direction } = useSwipe(target, {
  passive: false,
  onSwipeEnd: (e: TouchEvent, direction: UseSwipeDirection) => {
    if (!direction) return
    moveItem(direction)
  }
})
</script>

<style scoped></style>
